import pandas as pd
import numpy as np
import json
import sys
import warnings
from sklearn.feature_selection import f_classif
from scipy.stats import f_oneway
warnings.filterwarnings('ignore')

def select_top_features_with_mandatory(f_scores, mandatory_fields=['rcyl', 'rcql', 'ljcyl', 'ljcql', 'qyb'], max_features=20):
    """
    选择前20个特征，确保包含必须字段，并且这5个字段尽量排在前面
    """
    mandatory_fields_lower = [field.lower() for field in mandatory_fields]

    # 按F值排序所有字段
    sorted_features = sorted(f_scores.items(), key=lambda x: x[1], reverse=True)

    selected = []
    mandatory_f_scores = []
    other_f_scores = []

    # 分离必须字段和其他字段
    for field, score in sorted_features:
        if field.lower() in mandatory_fields_lower:
            mandatory_f_scores.append((field, score))
        else:
            other_f_scores.append((field, score))

    # 必须字段按F值排序
    mandatory_f_scores.sort(key=lambda x: x[1], reverse=True)

    # 先添加必须字段
    mandatory_added = []
    for field, score in mandatory_f_scores:
        selected.append(field)
        mandatory_added.append(field)

    # 然后添加其他高F值字段，确保总数不超过max_features
    for field, score in other_f_scores:
        if len(selected) >= max_features:
            break
        selected.append(field)

    return selected, mandatory_added

def calculate_anova_scores(df, target_col='qyb'):
    """
    计算方差分析F值
    """
    # 将目标变量离散化为分类变量
    target = df[target_col].dropna()

    # 使用分位数将连续变量转换为分类变量
    try:
        # 计算四分位数
        q1, q2, q3 = target.quantile([0.25, 0.5, 0.75])
        target_categorical = pd.cut(target,
                                    bins=[-np.inf, q1, q2, q3, np.inf],
                                    labels=['低', '中下', '中上', '高'])
    except Exception as e:
        # 如果分位数计算失败，使用简单的二分类
        median_val = target.median()
        target_categorical = pd.cut(target,
                                    bins=[-np.inf, median_val, np.inf],
                                    labels=['低', '高'])

    f_scores = {}
    numeric_cols = df.select_dtypes(include=[np.number]).columns.tolist()

    for col in numeric_cols:
        if col == target_col:
            # qyb作为目标变量，给予最高的F值
            f_scores[col] = float('inf')  # 使用无穷大表示最重要
            continue

        col_data = df[col].dropna()

        # 找到公共索引
        common_idx = target_categorical.index.intersection(col_data.index)
        if len(common_idx) < 10:  # 至少需要10个样本
            continue

        # 获取对应的数据
        feature_values = col_data.loc[common_idx]
        target_groups = target_categorical.loc[common_idx]

        # 按分组分离特征值
        groups = []
        for group_name in target_groups.cat.categories:
            group_data = feature_values[target_groups == group_name]
            if len(group_data) > 0:
                groups.append(group_data.values)

        # 计算F统计量
        if len(groups) >= 2:
            try:
                f_stat, p_val = f_oneway(*groups)
                if not np.isnan(f_stat) and not np.isinf(f_stat):
                    f_scores[col] = f_stat
            except Exception as e:
                print(f"计算 {col} 的F值时出错: {e}")
                continue

    return f_scores

def main(csv_file_path):
    try:
        print(f"开始第一次方差分析，数据文件: {csv_file_path}")

        # 读取CSV数据
        df = pd.read_csv(csv_file_path)
        print(f"数据形状: {df.shape}")

        # 确保qyb字段存在
        if 'qyb' not in df.columns:
            result = {
                'status': 'error',
                'message': 'qyb字段不存在于数据中'
            }
            print(json.dumps(result))
            return

        # 获取所有数值字段
        numeric_features = df.select_dtypes(include=[np.number]).columns.tolist()
        print(f"找到 {len(numeric_features)} 个数值特征字段")

        # 计算方差分析F值
        f_scores = calculate_anova_scores(df, 'qyb')

        # 将无穷大的F值（qyb）转换为一个很大的数值用于排序
        processed_f_scores = {}
        for feature, score in f_scores.items():
            if feature == 'qyb':
                processed_f_scores[feature] = 999999.0  # 给qyb一个很大的F值
                print(f"{feature}: F值 = 999999.0000 (目标变量)")
            else:
                processed_f_scores[feature] = score
                print(f"{feature}: F值 = {score:.4f}")

        print(f"成功计算了 {len(processed_f_scores)} 个字段的F值")

        # 定义必须包含的字段
        mandatory_fields = ['rcyl', 'rcql', 'ljcyl', 'ljcql', 'qyb']

        # 选择前20个特征，确保包含必须字段
        top_20_features, mandatory_included = select_top_features_with_mandatory(
            processed_f_scores, mandatory_fields, 20)

        print(f"选择的前20个特征: {top_20_features}")
        print(f"必须字段包含情况: {mandatory_included}")

        # 检查缺失的必须字段
        missing_mandatory = []
        for field in mandatory_fields:
            field_found = False
            for included_field in mandatory_included:
                if included_field.lower() == field.lower():
                    field_found = True
                    break
            if not field_found:
                missing_mandatory.append(field)

        # 返回结果
        result = {
            'top_20_features': top_20_features,
            'f_scores': {k: (v if v != 999999.0 else 'target_variable') for k, v in processed_f_scores.items()},
            'mandatory_fields': mandatory_fields,
            'mandatory_included': mandatory_included,
            'missing_mandatory': missing_mandatory,
            'total_features_analyzed': len(numeric_features),
            'valid_f_scores_count': len(processed_f_scores),
            'data_shape': df.shape,
            'target_variable': 'qyb',
            'analysis_method': 'ANOVA (方差分析)',
            'status': 'success'
        }

        print(json.dumps(result))

    except Exception as e:
        error_result = {
            'status': 'error',
            'message': f'第一次方差分析失败: {str(e)}'
        }
        print(json.dumps(error_result))

if __name__ == "__main__":
    if len(sys.argv) != 2:
        print(json.dumps({
            'status': 'error',
            'message': '参数错误，需要提供CSV文件路径'
        }))
    else:
        main(sys.argv[1])
